Framework / DOM / DOM Basics / Meta Units
In This Topic
    Meta Units
    In This Topic
     Meta Units Overview
    Meta units are objects that derive from the NMetaUnit class. The purpose of meta units is to allow you to attach arbitrary custom meta data to schemas, properties and child slots. That is why you can think of meta units as the NOV equivalent to CLR attributes. Unlike CLR attributes however, the usage of meta units is performed without reflection, which means that meta units are significantly faster to assign and query for than CLR attributes.
     Creating And Assigning Meta Units

    Creating meta units is easy - you just need to create an object that derives from the NMetaUnit class. This object can then be assigned to schemas, properties and child slots via the respective SetMetaUnit method. When you later need to obtain an instance of a specific meta unit you need to pass the type of the meta unit to the respective GetMetaUnit method. The following code example demonstrates how to work with meta units:

    My First Meta Unit
    Copy Code
    public class MyMetaUnit : NMetaUnit
    {
        public MyMetaUnit(int data)
        {
            Data = data;
        }
        public int Data;
    }
    
    public class MyNodeWithMetaUnits : NNode
    {
        public MyNodeWithMetaUnits() { }
        static MyNodeWithMetaUnits()
        {
            MyNodeWithMetaUnitsSchema = NSchema.Create(typeof(MyNodeWithMetaUnits), NNode.NNodeSchema);
            MyNodeWithMetaUnitsSchema.SetMetaUnit(new MyMetaUnit(10));
            P1Property = MyNodeWithMetaUnitsSchema.AddSlot("P1", NDomType.String, "");
            P1Property.SetMetaUnit(new MyMetaUnit(20));
            P2Property = MyNodeWithMetaUnitsSchema.AddSlot("P2", NDomType.Boolean, "");
        }
        //...
        public static readonly NSchema MyNodeWithMetaUnitsSchema;
        public static readonly NProperty P1Property;
        public static readonly NProperty P2Property;
    }
    ...
    
    public static void TestMetaUnits()
    {
        MyNodeWithMetaUnits node = new MyNodeWithMetaUnits();
        OutputMyMetaUnits(node);
        // output is:
        // MyMetaUnit value for My Node With Meta Units Schema is 10
        // MyMetaUnit is not set for Tag
        // MyMetaUnit value for P1 is 20
        // MyMetaUnit is not set for P2
    }
    public static void OutputMyMetaUnits(NNode node)
    {
        // try get meta unit from schema
        MyMetaUnit myMetaUnit = (MyMetaUnit)node.Schema.GetMetaUnit(typeof(MyMetaUnit));
        OutputMyMetaUnit(myMetaUnit, node.Schema);
        // try get meta unit from properties
        INIterator<NProperty> it = node.Schema.GetPropertyIterator();
        while (it.MoveNext())
        {
            NProperty property = it.Current;
            myMetaUnit = (MyMetaUnit)property.GetMetaUnit(node.Schema, typeof(MyMetaUnit));
            OutputMyMetaUnit(myMetaUnit, property);
        }
    }
    public static void OutputMyMetaUnit(MyMetaUnit myMetaUnit, object container)
    {
        if (myMetaUnit != null)
        {
            Console.WriteLine("MyMetaUnit value for " + container.ToString() + " is " + myMetaUnit.Data);
        }
        else
        {
            Console.WriteLine("MyMetaUnit is not set for " + container.ToString());
        }
    }
    

    As you can see creating and assigning a custom meta unit is fairly easy - you just need to create an object that derives from the NMetaUnit class. An instance of that object can later be applied to schemas, properties and child slots. In our example the MyMetaUnit class derives from NMetaUnit and simply holds an integer value. Instances of MyMetaUnit are applied to the schema of the MyNodeWithMetaUnits node (with value of 10) and to its P1 property (with value of 20).

    The TestMetaUnits method simply creates a node from the MyNodeWithMetaUnits class and passes it to the OutputMyMetaUnits method, which inspects the passed node schema and properties for instances of the MyMetaUnit class and outputs their value for a specific meta object (in our example - schema or property).

     Meta Units Appliance

    The MyMetaUnit class can be applied to schemas, properties and child slots of any node. There are cases however when it makes no sence to apply a specific meta unit to a schema, property or child slot. To help you validate your code for such appliances the NMetaUnit class defines the GetAppliance() virtual method, which returns a value from the ENMetaUnitAppliance mask. The following code example extends the MyMetaUnit class, by overriding the GetAppliance() method in order to prohibit the appliance of the meta unit to child slots:

    Meta Units Appliance
    Copy Code
    public class MyMetaUnit : NMetaUnit
    {
        public MyMetaUnit(int data)
        {
            Data = data;
        }
        public override ENMetaUnitAppliance GetAppliance()
        {
            // allow the meta unit to be set only to schemas and properties
            return ENMetaUnitAppliance.Schemas | ENMetaUnitAppliance.Properties;
        }
        protected override void OnApplying(NSchema schema, object container)
        {
            base.OnApplying(schema, container);
            // TODO: add your meta unit on OnApplying code here
        }
        protected override void OnApplied(NSchema schema, object container)
        {
            base.OnApplied(schema, container);
            // TODO: add your meta unit OnApplied code here
        }
        public int Data;
    }
    

    More advanced meta units may need to know when they are about to be applied or have been applied to a specific schema, property or child slot. This is achieved by overriding the OnApplying and OnApplied protected virtual methods respectively. The passed container object is an instance of the schema, property or child slot that contains the meta unit.